package com.xxx.service.impl;

import com.xxx.config.HighlightResultMapper;
import com.xxx.doc.CourseDoc;
import com.xxx.dto.CourseSearchDto;
import com.xxx.repository.CourseDocRepository;
import com.xxx.result.PageList;
import com.xxx.service.ICourseDocService;
import com.xxx.vo.AggrPageList;
import com.xxx.vo.MyBucket;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;  
import org.elasticsearch.search.aggregations.HasAggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;

import java.util.*;


@Service
public class CourseDocServiceImpl implements ICourseDocService {

    @Autowired
    private CourseDocRepository courseDocRepository;

    @Autowired
    private ElasticsearchRestTemplate elasticsearchTemplate;

    @Autowired
    private HighlightResultMapper highlightResultMapper;

    @Override
    public void save(CourseDoc courseDoc) {
        courseDocRepository.save(courseDoc);
    }

    /**
     * 搜索实现
     */
    @Override
    public PageList<CourseDoc> search(CourseSearchDto courseSearchDto) {
        //创建查询对象
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();

        //分页
        if (courseSearchDto.getSortField() != null && courseSearchDto.getSortType() != null) {

        }
        nativeSearchQueryBuilder.withPageable(PageRequest.of(courseSearchDto.getPage() - 1, courseSearchDto.getRows()));
        //排序
        //FieldSortBuilder sortBuilder = new FieldSortBuilder("price").order(SortOrder.ASC);
        //排序字段处理
        String sortField = "price";
        if (StringUtils.isNotBlank(courseSearchDto.getSortField())) {
            switch (courseSearchDto.getSortField()) {
                case "xl":
                    sortField = "saleCount";
                    break;
                case "xp":
                    sortField = "onlineTime";
                    break;
                case "pl":
                    sortField = "commentCount";
                    break;
                case "rq":
                    sortField = "viewCount";
                    break;
            }
        }

        //排序方式处理
        SortOrder sortOrder = SortOrder.DESC;
        if ("asc".equals(courseSearchDto.getSortType())) {
            sortOrder = SortOrder.ASC;
        }
        FieldSortBuilder sortBuilder = SortBuilders.fieldSort(sortField).order(sortOrder);
        nativeSearchQueryBuilder.withSort(sortBuilder);


        //搜索 查询:keyword
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if (StringUtils.isNotBlank(courseSearchDto.getKeyword())) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("name", courseSearchDto.getKeyword()));
        }

        //过滤:chargeName,courseTypeId,gradeName,price
        if (StringUtils.isNotBlank(courseSearchDto.getChargeName())) {
            Integer chargeType = "免费".equals(courseSearchDto.getChargeName()) ? 1 : 2;
            boolQueryBuilder.filter(QueryBuilders.termQuery("charge", chargeType));
        }
        //过滤:courseTypeId 课程类型
        if (courseSearchDto.getCourseTypeId() != null) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("courseTypeId", courseSearchDto.getCourseTypeId()));
        }
        //过滤:gradeName 课程等级
        if (StringUtils.isNotBlank(courseSearchDto.getGradeName())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("gradeName", courseSearchDto.getGradeName()));
        }
        //过滤:price 价格区间
        if (courseSearchDto.getPriceMin() != null) {
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(courseSearchDto.getPriceMin()));
        }
        if (courseSearchDto.getPriceMax() != null) {
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").lte(courseSearchDto.getPriceMax()));
        }
        nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
        //高亮
        nativeSearchQueryBuilder.withHighlightFields(new HighlightBuilder.Field("name").preTags(
                "<font style='color:red'>").postTags("</font>"));
        //聚合查询
        //增加聚合条件
        //第一个是随便起的名字,第二个是聚合的字段要对应上
        TermsAggregationBuilder aggregationBuilder1 =
                AggregationBuilders.terms("gradeName").field("gradeName");
        TermsAggregationBuilder aggregationBuilder2 =
                AggregationBuilders.terms("chargeName").field("charge");
        nativeSearchQueryBuilder.addAggregation(aggregationBuilder1).addAggregation(aggregationBuilder2);


        SearchQuery searchQuery = nativeSearchQueryBuilder.build();
        AggregatedPage<CourseDoc> courseDocs = elasticsearchTemplate.queryForPage(searchQuery,
                CourseDoc.class,
                highlightResultMapper);
        //处理聚合结果
        Aggregations aggregations = courseDocs.getAggregations();
        //获取到的所有的(2个)聚合结果 key是名字,value是桶
        Map<String, Aggregation> aggrMaps = aggregations.asMap();
        //最终返回的
        HashMap<String, List<MyBucket>> aggrResultMap = new HashMap<>();
        //获取所有的聚合结果
        Set<Map.Entry<String, Aggregation>> entries = aggrMaps.entrySet();

        //遍历
        for (Map.Entry<String, Aggregation> entry : entries) {
            //聚合名称
            String aggrNames = entry.getKey();
            //所有聚合结果--->桶
            Aggregation aggregation = entry.getValue(); //一会儿打断点
            //声明一个list装mybucket
            ArrayList<MyBucket> myBuckets = new ArrayList<>();
            if (aggregation instanceof ParsedLongTerms) {//聚合结果是数字
                ParsedLongTerms longAggregation = (ParsedLongTerms) aggregation;
                //获取所有桶
                List<? extends Terms.Bucket> buckets = longAggregation.getBuckets();
                for (Terms.Bucket bucket : buckets) {
                    String key = "1".equals(bucket.getKeyAsString()) ? "免费" : "收费";
                    long docCount = bucket.getDocCount();
                    MyBucket myBucket = new MyBucket(key, docCount);
                    //添加
                    myBuckets.add(myBucket);
                }
            } else {//聚合结果是字符串
                ParsedStringTerms stringAggregation = (ParsedStringTerms) aggregation;
                List<? extends Terms.Bucket> buckets = stringAggregation.getBuckets();
                for (Terms.Bucket bucket : buckets) {
                    //处理参数
                    String key = bucket.getKeyAsString();
                    long docCount = bucket.getDocCount();
                    MyBucket myBucket = new MyBucket(key, docCount);
                    //添加
                    myBuckets.add(myBucket);
                }
            }
            aggrResultMap.put(aggrNames, myBuckets);
        }
        //返回结果
        // 总记录数
        long total = courseDocs.getTotalElements();
        // 当前页数据
        List<CourseDoc> content = courseDocs .getContent();
        //返回最终结果
        return new AggrPageList<>(total, content, aggrResultMap);
    }
}
